# -*- coding: utf-8 -*-

from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
from datetime import datetime
from odoo import SUPERUSER_ID

TYPE = [('materials', 'production materials'), ('no_materials', 'Non-production materials')]
STATE = [
    ('draft', 'Draft'),
    ('wait_approval', 'Waiting for Approval'),
    ('approved', 'Approved'),
    ('rejected', 'Rejected'),
    ('done', 'Done')]


class ProductApply(models.Model):
    _name = 'product.apply'
    _description = 'product apply'
    _inherit = ['mail.thread', 'mail.activity.mixin']
    _seq_prefix = 'PA'
    _order = 'id desc'

    number = fields.Char('Number', default='/', readonly=True)
    name = fields.Char('name', readonly=True, related='number', copy=False)
    department_id = fields.Many2one('hr.department', string='Department', domain="[('parent_id', '=', False)]")
    apply_uid = fields.Many2one('res.users', string='apply uid',
                                default=lambda self: self.env.user.id if not self.env.user._is_public() else False)
    date = fields.Date('Date', default=fields.Date.context_today, copy=False)
    type = fields.Selection(TYPE, string='type', required=True)
    state = fields.Selection(STATE, string='state', default='draft', compute='_compute_state', store=True)
    line_ids = fields.One2many('product.apply.line', 'parent_id', string='product apply line')
    product_id = fields.Many2one('product.template', 'Product', related='line_ids.product_id', readonly=True)

    note = fields.Text('note')
    confirm_date = fields.Datetime(string='confirm date', readonly=True)
    confirm_uid = fields.Many2one('res.users', string='confirm uid', readonly=True)
    done_date = fields.Datetime(string='done date', readonly=True)
    done_uid = fields.Many2one('res.users', string='done uid', readonly=True)

    # 审批流

    sb_workflow_template_id = fields.Many2one('sb.workflow.template', string="Approval Workflow Template",
                                              domain="[('sb_workflow_template_item_ids', '!=', False),"
                                                     "('workflow_type', 'in', ['other', 'product_apply'])]")
    sb_workflow_id = fields.Many2one('sb.workflow', string="Current Approval Workflow", copy=False)
    sb_workflow_state = fields.Selection(related="sb_workflow_id.state",
                                         readonly=True, store=True,
                                         string="Approval Status")
    sb_workflow_item_ids = fields.One2many(related="sb_workflow_id.sb_workflow_item_ids", string="Approval Items")
    sb_workflow_attachments_ids = fields.One2many(related="sb_workflow_id.sb_workflow_attachments_ids",
                                                  string="Approval Attachments")
    sb_workflow_ids = fields.One2many('sb.workflow', 'product_apply_id', string="Approval Workflows")

    operation_ids = fields.Many2many('mrp.routing.workcenter',
                                     relation="mrp_routing_workcenter_product_apply_rel",
                                     column1="operation_id", column2="product_apply_id",
                                     string="operations")
    picking_ids = fields.One2many('stock.picking', 'apply_id', string='Pickings')
    work_station_id = fields.Many2one('work.station', string='Work Station')

    def unlink(self):
        """
        删除时检查状态，允许草稿状态删除
        """
        if self.filtered(lambda x: x.state != 'draft'):
            raise ValidationError(_("删除出错，只允许草稿状态删除!"))
        ret = super(ProductApply, self).unlink()
        return ret

    @api.depends('sb_workflow_state')
    def _compute_state(self):
        for item in self:
            if item.sb_workflow_state == 'approve':
                item.state = 'approved'
            elif item.sb_workflow_state == 'approval':
                item.state = 'wait_approval'
            elif item.sb_workflow_state == 'fail_to_approve':
                item.state = 'rejected'
            else:
                item.state = 'draft'

    def action_picking_ids(self):
        self = self.sudo()
        self.ensure_one()
        view_id = self.env.ref('stock.view_picking_form').id
        if len(self.picking_ids) > 1:
            return {
                'name': _('picking form'),
                'res_model': 'stock.picking',
                'view_mode': 'tree,form',
                'type': 'ir.actions.act_window',
                'domain': [('id', 'in', self.picking_ids.ids)],
            }
        else:
            return {
                'name': _('picking form'),
                'res_model': 'stock.picking',
                'view_mode': 'form',
                'view_id': view_id,
                'type': 'ir.actions.act_window',
                'res_id': self.picking_ids.id,
            }

    @api.constrains('sb_workflow_state')
    def _constraint_sb_workflow_state(self):
        for record in self:
            if record.sb_workflow_state == 'approve' and record.state != 'done':
                record.do_done()

    @api.onchange('sb_workflow_state')
    def _onchange_compute_state(self):
        self._compute_state()

    @api.onchange('department_id')
    def _onchange_department_id(self):
        if self.department_id.is_production == True:
            self.type = 'materials'
        else:
            self.type = 'no_materials'

    def create_workflow(self):
        for record in self.line_ids:
            if record.apply_qty > record.qty_available:
                raise ValidationError(_('The product %s is not enough in stock') % record.product_id.name)
        if self.sb_workflow_template_id:
            # 判断库存是否足够, 如果库存不足，则不允许创建审批流
            for line in self.line_ids:
                if line.product_id.type == 'product' and line.qty_available < line.qty:
                    raise ValidationError(_('The product %s is not enough in stock') % line.product_id.name)
            if len(self.sb_workflow_ids) > 0:
                workflow_sum = len(self.sb_workflow_ids) + 1
            else:
                workflow_sum = 1
            self.state = 'wait_approval'
            if self.name == 'Draft' or not self.name:
                self.name = self.env['ir.sequence'].next_by_code('product.apply.serial')
            # 创建审批流
            new_wf_id = self.env['sb.workflow'].sudo().create({
                'name': self.name + '- Approval Flow' + '-' + str(workflow_sum),
                'approval_time': fields.Datetime.now(),
                'workflow_type': 'product_apply',
                'product_apply_id': self.id,
            })
            self.sb_workflow_id = new_wf_id.id
            # self.requisition_date = fields.Date.today()
            # 根据模板生成审批项
            item_audit_levels = []
            for item in self.sb_workflow_template_id.sb_workflow_template_item_ids:
                new_item = self.env['sb.workflow.item'].sudo().create({
                    'name': item.name,
                    'user_group_ids': item.user_group_ids.ids,
                    'audit_level': item.audit_level,
                    'sb_workflow_id': new_wf_id.id,
                    'state': 'wait_forward'
                })
                # 收集生成的审核项的所有层级
                item_audit_levels.append(new_item.audit_level)
            # 去重排序
            item_audit_levels = list(set(item_audit_levels))
            item_audit_levels.sort()
            # 开放最低层级的神匹配
            for n_item in new_wf_id.sb_workflow_item_ids:
                if n_item.audit_level == item_audit_levels[0]:
                    n_item.state = 'approval'
        else:
            raise ValidationError('Please select an approval template.')

        # self.write({'state': 'confirm', 'confirm_date': datetime.now(), 'confirm_uid': self.env.user.id})

    @api.depends('sb_workflow_ids')
    def _compute_sb_workflow_ids_sum(self):
        for item in self:
            if item.sb_workflow_ids:
                item.sb_workflow_ids_sum = len(item.sb_workflow_ids)
            else:
                item.sb_workflow_ids_sum = 0

    def action_view_workflow(self):
        return {
            'name': 'Approval Flow',
            'type': 'ir.actions.act_window',
            'res_model': 'sb.workflow',
            'view_mode': 'tree',
            'target': 'current',
            'domain': [('product_apply_id', '=', self.id)],
        }

    def action_workflow(self):
        return {
            'name': 'Approval Flow',
            'type': 'ir.actions.act_window',
            'res_model': 'sb.workflow',
            'view_mode': 'form',
            'res_id': self.sb_workflow_id.id,
            'target': 'current',
        }

    def do_confirm(self):
        self.write({'state': 'confirm', 'confirm_date': datetime.now(), 'confirm_uid': self.env.user.id})

    def do_done(self):
        self = self.sudo()
        vals_list = []
        picking_model = self.env['stock.picking'].with_user(SUPERUSER_ID)
        partner_model = self.env['res.partner'].with_user(SUPERUSER_ID)
        for item in self:
            partner_id = partner_model.search([('user_id', '=', item.apply_uid.id)], limit=1)
            xml_id = 'sb_stock_inherit.picking_type_production_feed' if item.type == 'materials' else 'sb_stock_inherit.picking_type_article_picking'
            picking_type_id = self.env.ref(xml_id)
            move_ids_without_package = []
            for line in item.line_ids:
                move_ids_without_package.append((0, 0, {
                    'name': line.product_id.name,
                    'product_id': line.product_id.product_variant_id.id,
                    # 'quantity': line.qty,
                    'product_uom_qty': line.qty,
                    'product_uom': line.uom_id.id,
                    'location_id': picking_type_id.default_location_src_id.id if picking_type_id and picking_type_id.default_location_src_id else False,
                    'location_dest_id': picking_type_id.default_location_dest_id.id if picking_type_id and picking_type_id.default_location_dest_id else False,
                }))
            value = {
                'partner_id': partner_id.id if partner_id else False,
                'picking_type_id': picking_type_id.id if picking_type_id else False,
                'scheduled_date': item.date,
                'res_order': '%s,%s' % (item._name, item.id),
                'origin': item.number,
                'user_id': item.apply_uid.id,
                'move_ids_without_package': move_ids_without_package,
                'apply_id': self.id,
                'work_station_id': self.work_station_id.id,
                'apply_uid': self.apply_uid.id
            }
            vals_list.append(value)
        if vals_list:
            new_spicking_ids = picking_model.create(vals_list)
            for res in new_spicking_ids:
                res.action_assign()
        self.write({'state': 'done', 'done_date': datetime.now(), 'done_uid': self.env.user.id})

    @api.model_create_multi
    def create(self, vals_list):
        for vals in vals_list:
            # 自动创建编码
            if vals.get('number', '/') == '/':
                seq_rec = self.create_default_sequence()
                vals.update({
                    'number': seq_rec._next()
                })
            # 明细不可为空
            if not vals.get('line_ids'):
                raise ValidationError('Please enter the details.')
        return super(ProductApply, self).create(vals_list)

    def write(self, values):
        res = super(ProductApply, self).write(values)
        if not self.line_ids:
            raise ValidationError('Please enter the details.')
        return res

    def create_default_sequence(self):
        # 查找序列号
        seq_rec = self.env['ir.sequence'].sudo().search([('code', '=', 'product.apply.serial')], limit=1)
        if not seq_rec:
            prefix = '%(year)s%(month)s%(day)s' if not self._seq_prefix else str(
                self._seq_prefix) + '%(year)s%(month)s%(day)s'
            seq_val = {
                'name': 'Product Apply',
                'code': 'product.apply.serial',
                'prefix': prefix,
                'padding': 3,
                'number_next': 1,
                'number_increment': 1,
            }
            seq_rec = self.env['ir.sequence'].sudo().create(seq_val)
        return seq_rec

    @api.onchange('apply_uid')
    def onchange_apply_uid(self):
        for record in self:
            record.department_id = record.apply_uid.department_id


class ProductApplyLine(models.Model):
    _name = 'product.apply.line'
    _description = 'Product Apply Line'

    parent_id = fields.Many2one('product.apply', string='Product Apply', index=True, ondelete='cascade')
    product_id = fields.Many2one('product.template', string='product', required=True, index=True)
    s_product_id = fields.Many2one('product.product', string='product', related='product_id.product_variant_id',
                                   store=True)
    default_code = fields.Char(string='Product Code', related='product_id.default_code')
    qty = fields.Float(string='quantity', default=0, required=True)
    # 申请数量, 经过单位转换后
    apply_qty = fields.Float(string='apply quantity', default=0, readonly=True)
    # 库存单位
    s_product_uom_id = fields.Many2one('uom.uom', string="stock uom", store=True, related='product_id.uom_id')
    # 申领单位
    uom_id = fields.Many2one('uom.uom', string="apply uom", store=True, readonly=True, related='product_id.uom_po_id')
    qty_available = fields.Float(string='quantity available', related='s_product_id.s_actual_quantity')
    subtotal = fields.Float(string='subtotal', compute='_compute_subtotal', store=True, digits=(10, 4))
    # 币种
    currency_id = fields.Many2one('res.currency', string='Currency', compute='_compute_subtotal', store=True)

    @api.onchange('uom_id', 's_product_uom_id', 'qty')
    def _onchange_uom(self):
        for record in self:
            if record.uom_id and record.s_product_uom_id:
                record.apply_qty = record.uom_id._compute_quantity(record.qty, record.s_product_uom_id)
            else:
                record.apply_qty = record.qty

    @api.depends('product_id', 'qty')
    def _compute_subtotal(self):
        for record in self:
            record.subtotal = 0
            quant_ids = self.env['stock.quant.report'].search([('product_id', '=', record.s_product_id.id)])
            total = 0
            qty = 0
            record.currency_id = False
            # 多批次加权单价
            for quant in quant_ids:
                line = quant.lot_id.purchase_order_ids.order_line.filtered(
                    lambda x: x.product_id == record.s_product_id)

                if not line:
                    continue
                record.currency_id = line[0].currency_id
                p = 0
                q = 0
                for i in line:
                    p += i.price_unit * i.product_uom_qty
                    q += i.product_uom_qty
                p_price_unit = p / q
                price = record.uom_id._compute_price(p_price_unit, record.s_product_uom_id)
                total += price * quant.quantity
                qty += quant.quantity
            if qty > 0:
                price_unit = total / qty
                record.subtotal = price_unit * record.apply_qty
            else:
                record.subtotal = 0
